/*========================Includes========================*/

#include "Types.h"
#include <WinSock2.h>
#include "ServerClientTools.h"
#include "SocketSendRecvTools.h"
#include "GeneralFunctions.h"
#include "Algorithms.h"

/*============Internal Functions Decleration=============*/
/*
  * Receive Battery Action
  * =========================
  * This function implements a loop of receiving actions
  *from the battery until receiving an end of round action 
  * Arguments: using global arguments
  * Return Value: None
  */ 
void ReceiveBatteryAction ();

/*
 * UpdateSimulator
 * =========================
 * According to the interceptor status this message sends the information needed to the simulator. 
 */
void UpdateSimulator();



/*====================Global Paramaters====================*/
	char *SelfIP; 
	int SelfPort ;
	char *ClockIP;
	int ClockPort;
	char *BatteryIP; 
	int BatteryPort ;
	char *SimulatorIP; 
	int SimulatorPort ;
	double InterceptorSpeed; 
	double MinInterceptionRadius; 
	double InterceptionProbability; 
	TActionType ActionType;
	int Received, RoundNum;
	TVector Position, Velocity;
	int RocketID;
	TVector ChasedRocketPosition, ChasedRocketVelocity;
	TVector Direction; 
	TM_Status Status;
	int RoundNumber;
	SOCKET ClockSocket, BatterySocket, SimulatorSocket;


/*=====================Main function=====================*/

void MainInterceptor(int argc, char *argv[])
{	
	SelfIP = argv[2];
	SelfPort = atoi(argv[3]);
	ClockIP = argv[4];
	ClockPort = atoi(argv[5]);
	BatteryIP = argv[6];
	BatteryPort = atoi(argv[7]);
	SimulatorIP = argv[8];
	SimulatorPort = atoi(argv[9]);
	InterceptorSpeed = atof(argv[10]);
	MinInterceptionRadius = atof(argv[11]);
	InterceptionProbability = atof(argv[12]);
	RocketID =-1;
	Status = M_STATUS_IN_BATTERY;
	RoundNumber = 0;
	
	
	// Start up sequence
	printf("Trying to connect to battery %s , %d\n",BatteryIP, BatteryPort);
	
	//Connect as clinet to Battery
	BatterySocket = StartClientAndConnectToServer(BatteryIP, BatteryPort);
	SendActionType(ACTION_REGISTRATION, BatterySocket);
	
	//Recieve initial position
	ReceiveVector(&Position,BatterySocket);
	printf("Recieved battery position:  (%.3g, %.3g)", Position.x,Position.y);

	//Connect as client To Simulator
	printf("Trying to connect to simulator\n");
	SimulatorSocket = StartClientAndConnectToServer(SimulatorIP, SimulatorPort); 
	printf("Connected to simulator. Now identifying as interceptor\n");
	IdentifyToServer(MODE_INTERCEPTOR,SimulatorSocket);
	
	//Connect as client to Clock
	printf("trying to connect to clock\n");
	ClockSocket = StartClientAndConnectToServer(ClockIP, ClockPort);
	printf("connected to clock\n");
	FinishedStartUpSequence();

	/**** END OF Start up sequence ****/

	printf("Waiting for clockstart\n");
	RoundNum = WaitForClockToNotifyBeginningOfRound(ClockSocket);
	if (RoundNum == -1)
	{
		PrintErrorAndExit(ERROR_RECEIVING_MESSAGE);
	}
	
	Velocity.x = 0;
	Velocity.y = 0;
	
	//// While the intercetor is in the battery
	while(Status == M_STATUS_IN_BATTERY)
	{
		Received = ReceiveActionType(&ActionType,BatterySocket);
		switch (ActionType)
		{
			case ACTION_LAUNCH_INTERCEPTOR:
				ReceiveInteger(&RocketID,BatterySocket);
				ReceiveVector(&ChasedRocketPosition,BatterySocket);
				ReceiveVector(&ChasedRocketVelocity,BatterySocket);
				Velocity = DetermineInterceptorDirection(ChasedRocketPosition, 
							ChasedRocketVelocity,Position,InterceptorSpeed);				
				//sending initial information to Simulaotr
				SendActionType(ACTION_INITIAL_INTERCEPTOR_INFO_UPDATE,SimulatorSocket);
				SendInteger(RocketID,SimulatorSocket);
				SendVector(Position,SimulatorSocket);
				SendVector(Velocity,SimulatorSocket);
				SendDouble(MinInterceptionRadius ,SimulatorSocket);
				SendDouble(InterceptionProbability,SimulatorSocket);
				Status = M_STATUS_ACTIVE;
				//Recieve Actions from batteries as airbor interceptor
				ReceiveBatteryAction ();
				break;

			case ACTION_UPDATE_INTERCEPTOR_ON_ROCKET_INFO:
				ReceiveVector(&ChasedRocketPosition, BatterySocket);
				ReceiveVector(&ChasedRocketVelocity, BatterySocket);
				Velocity = DetermineInterceptorDirection(ChasedRocketPosition, 
										ChasedRocketVelocity,Position,InterceptorSpeed);
				//sending information to Simulaotr
				//SendActionType(ACTION_UPDATE_CURRENT_DIRECTION,SimulatorSocket);
				//SendVector(Velocity,SimulatorSocket);
				break;

			case ACTION_END_OF_ROUND:
				UpdateSimulator();
				NotifyClockEndOfRound(ClockSocket);
				RoundNum = WaitForClockToNotifyBeginningOfRound(ClockSocket);
				if (RoundNum == -1)
				{
					PrintErrorAndExit(ERROR_RECEIVING_MESSAGE);
				}
				break;
		}
	}



	// Receiving actions after the Interceptor was launched

	while(1)
	{
		/*First we recieve Interceptor Position or Intercetion Occurence
		in case we dont need to wait for battery*/
		Received = ReceiveActionType(&ActionType,SimulatorSocket);
		switch (ActionType)
		{
			//in case of Interception we can exit maininterceptor
			case ACTION_INTERCEPTED:
				printf("BOOOOOM intercepted Rocket %d",RocketID);
				closesocket(ClockSocket);
				PrintEndOfGame();
			//	getchar();
				exit (0);
				break;
			case ACTION_UPDATE_CURRENT_POSITION:
				ReceiveVector(&Position,SimulatorSocket);
				
				//Aftr Recieving New Position from the Simulator accept actions from battery
				ReceiveBatteryAction ();
				break;

			/*================ Recieved unused action =================*/
			default:
				printf("ERROR, unknown action: ");
				PrintActionType(ActionType);
		//	//	getchar();
				break;

		}
	}
}

/*======================Internal Functions======================*/
//Receive actions from battery
void ReceiveBatteryAction ()
{
	while(ActionType != ACTION_END_OF_ROUND)
		{
		ReceiveActionType(&ActionType,BatterySocket);
		switch (ActionType)
		{
		/*================ End Round =================*/
			case ACTION_END_OF_ROUND:
			//adding direction update here
			//SendActionType(ACTION_UPDATE_CURRENT_DIRECTION, SimulatorSocket);
			//SendVector(Velocity, SimulatorSocket);
			//SendActionType(ACTION_END_OF_ROUND,SimulatorSocket);
			printf("Chasing rocket #%d\n", RocketID);
			UpdateSimulator();
			NotifyClockEndOfRound(ClockSocket);
			RoundNum = WaitForClockToNotifyBeginningOfRound(ClockSocket);
			if (RoundNum == -1)
			{
				PrintErrorAndExit(ERROR_RECEIVING_MESSAGE);
			}
			break;

			/*============== Change Battery ===============*/
			case ACTION_NOTIFY_INTERCEPTOR_TO_CHANGE_BATTERY:
				{
				char *NewBatteryIP = NULL;
				int NewBatteryPort;
				ReceiveString(&NewBatteryIP,BatterySocket);
				ReceiveInteger(&NewBatteryPort,BatterySocket);
				//disconnect from ols battery
				closesocket(BatterySocket);
				printf("Closed connection with battery %s, %d.\n", BatteryIP, BatteryPort);
				//connect to new battery
				BatterySocket = StartClientAndConnectToServer(NewBatteryIP, NewBatteryPort);
				SendActionType(ACTION_CHANGE_BATTERIES, BatterySocket);
				SendInteger(RocketID, BatterySocket);
				printf("Successfuly changed batteries!\n");
				BatteryIP = NewBatteryIP;
				BatteryPort = NewBatteryPort;
				break;
				}
			
			/*================ Recieve Rocket info =================*/
			case ACTION_UPDATE_INTERCEPTOR_ON_ROCKET_INFO:
				ReceiveVector(&ChasedRocketPosition,BatterySocket);
				ReceiveVector(&ChasedRocketVelocity,BatterySocket);
				printf("Received current position and velocity of rocket\n");
				printf("Position: (%.3g, %.3g), Velocity: (%.3g, %.3g)\n", ChasedRocketPosition.x, ChasedRocketPosition.y, ChasedRocketVelocity.x, ChasedRocketVelocity.y);
				Velocity = DetermineInterceptorDirection(ChasedRocketPosition, 
							ChasedRocketVelocity,Position,InterceptorSpeed);
				//SendActionType(ACTION_UPDATE_CURRENT_DIRECTION,SimulatorSocket);
				//SendVector(Velocity,SimulatorSocket);
				break;
			/*================ Self Destruct if Rocket hit the ground =================*/
			case ACTION_SELF_DESTRUCT:
				printf("Oh no i missed Rocket %d how can i live with myself?!... \n  ...BOOM\n",RocketID);
				printf("Closing clock socket\n");
				closesocket(BatterySocket);
				closesocket(ClockSocket);
				printf("Closed clock socket\n");
				PrintEndOfGame();
			//	getchar();
				exit (0);	
				break;
			default:
				printf("ERROR\n");
			////	getchar(); 
				break;
			}
	}
}


//send status information to the simulator  
void UpdateSimulator()
{
	if (Status == M_STATUS_ACTIVE)
	{
		SendActionType(ACTION_UPDATE_CURRENT_DIRECTION, SimulatorSocket);
		SendVector(Velocity, SimulatorSocket);
	}
	else if (Status == M_STATUS_IN_BATTERY)
	{
		SendActionType(ACTION_IN_BATTERY, SimulatorSocket);
	}
	else
	{
		printf("ERROR: Unexpected rocket status. Failed sending info to simulator.\n");
		getchar();
	}
	SendActionType(ACTION_END_OF_ROUND, SimulatorSocket);
}
	